package com.jhw.ymcc.service.impl;


import com.jhw.ymcc.constants.RedisSmsConstants;
import com.jhw.ymcc.domain.MessageSms;
import com.jhw.ymcc.dto.RedisSmsDto;
import com.jhw.ymcc.exception.GlobalCustomException;
import com.jhw.ymcc.exception.GlobalErrorCode;
import com.jhw.ymcc.properties.SmsRegisterProperties;
import com.jhw.ymcc.service.IMessageSmsService;
import com.jhw.ymcc.service.IVerifyCodeService;
import com.jhw.ymcc.util.AssertUtil;
import com.jhw.ymcc.util.StrUtils;
import com.jhw.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author jhw
 * @since 2022/7/10
 */
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    // 业务高度封装：我们所有的调用都调用对方的service层，原因是如果有额外的处理，那么我们在service中完成，无需调用mapper层再进行处理，如果他的业务层额外处理，不是我们想要的可以自己封装一个
    @Autowired
    private IMessageSmsService messageSmsService;

    // 通过路径获取到application.yml中的值
//    @Value("${verifycode.smsregister.interval}")
//    private String interval;

    @Autowired
    private SmsRegisterProperties smsRegisterProperties;

    @Override
    public String getImageCode(String imageCodeKey) {
        if (imageCodeKey == null) {
            throw new GlobalCustomException("key无效");
        }
        //1.保存到redis【key - 传过来了，value - code】
        String code = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(imageCodeKey, code, 5, TimeUnit.MINUTES);

        //2.code进行编码base64
        String base64Str = VerifyCodeUtils.verifyCode(115, 42, code);

        //3.将base64编码之后的字符串响应到controller
        return base64Str;
    }

    @Override
    public void sendSmsCode(String phone) {
        // 1.参数校验，手机号格式校验
        // 断言：spring给我们提供了断言类
        // isNull：我断言你为null，你如果不是null就报错
        AssertUtil.isPhone(phone, GlobalErrorCode.PHONE_FORMAT_ERROR); // 我断言你不为Null，你如果为null，那么就报错

        // 2.做图形验证码校验，@TODO 自研

        // 3.拼接业务键，去Redis中查询Code
        // register:%s ，把你的%s替换成你的phone
        String rediskey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY, phone);
        Object obj = redisTemplate.opsForValue().get(rediskey);
        Date date = new Date();
        String code = "";
        if (obj != null){
            // 1.获取到value中的时间戳
            RedisSmsDto redisSmsDto = (RedisSmsDto)obj;
            // 2.判断是否过了1分钟，如果小于那么说明没超过，提示用户
            boolean boo  = (date.getTime() - redisSmsDto.getTime()) < smsRegisterProperties.getInterval(); // 判断间隔时间小于1分钟,如果小于一分钟为true，如果不小于为false
            AssertUtil.isFalse(boo, GlobalErrorCode.OPERATING_FREQUENTLY_ERROR);
            // 3.如果超过一分钟，那么继续沿用之前的code
            code = redisSmsDto.getCode();
        }else {
            // 1.如果不存在，那么我们生成一个验证码
            code = StrUtils.getRandomString(smsRegisterProperties.getCodesize());
        }
        // 4.将code+time存入到redis中
        RedisSmsDto redisSmsDto = new RedisSmsDto(code, date.getTime());
        redisTemplate.opsForValue().set(rediskey, redisSmsDto, smsRegisterProperties.getExpiredtime(), TimeUnit.MILLISECONDS);
        // 5.发送短信并存储日志
        sendMessageSms(date, code);
    }

    private void sendMessageSms(Date date, String code) {
        // 5.存储消息发送日志
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(smsRegisterProperties.getTitle());
        // 您的验证码为 817795 ,请在 10 分钟内使用
        String content = String.format(smsRegisterProperties.getContent(), code);
        messageSms.setContent(content);
        messageSms.setSendTime(date);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        messageSms.setIp(ip);
        messageSmsService.insert(messageSms);
        // 6.发送短信验证码
        log.info(content);
    }




}
